package com.lxit.cms.action.admin.assist.cn.util;

import com.lxit.cms.action.admin.assist.cn.msg.MsgCommand;
import com.lxit.cms.action.admin.assist.cn.msg.MsgDeliver;
import com.lxit.cms.action.admin.assist.cn.msg.MsgDeliverResp;
import com.lxit.cms.action.admin.assist.cn.msg.MsgHead;
import com.lxit.cms.action.admin.assist.cn.msg.MsgLogin;
import com.lxit.cms.action.admin.assist.cn.msg.MsgLoginResp;
import com.lxit.cms.action.admin.assist.cn.msg.MsgSubmit;
import com.lxit.cms.action.admin.assist.cn.msg.MsgSubmitResp;
/**
 * 
 * @desc: 对CMPP消息进行打包/解包方法实现
 * Connect/Submit/Delver及其应答消息的打包,解包完成
 * 问题:打解包方法是否要static,是否要synchronized?
 * @project:蓝杰中国移动Cmpp短信网关项目开发 Jun 17, 2009
 * @author: 蓝杰www.netjava.cn
 */
public class MsgTools {
	/**
	 * 将一个消息对象打包为字节组
	 * @param msg:要打包的消息对象
	 * @return:消息生成的字节数组
	 */
	public static  byte[] packMsg(MsgHead msg){
		int command=msg.getCommand_Id();
		java.io.ByteArrayOutputStream bous=new java.io.ByteArrayOutputStream();
		java.io.DataOutputStream dous=new java.io.DataOutputStream(bous);
		try{
		switch(command){
		case MsgCommand.CMPP_CONNECT ://打包登陆消息
			MsgLogin ml=(MsgLogin)msg;
			dous.writeInt(ml.getTotal_Length());
			dous.writeInt(ml.getCommand_Id());
			dous.writeInt(ml.getSequence_Id());
			
			Utils.writeString(dous, ml.getSource_Addr(), 6);
			 dous.write(ml.getAuthenticatorSource());
			 dous.writeByte(ml.getVersion());
			 dous.writeInt(Integer.parseInt(Utils.getMMDDHHMMSS()));
			 break;
		case MsgCommand.CMPP_CONNECT_RESP ://打包登陆应答消息
			MsgLoginResp mlr=(MsgLoginResp)msg;
			dous.writeInt(mlr.getTotal_Length());
			dous.writeInt(mlr.getCommand_Id());
			dous.writeInt(mlr.getSequence_Id());
			
			dous.writeInt(mlr.getStatus());
			dous.write(mlr.getAuthenticatorISMG());
			dous.write(mlr.getVersion());
			break;
		case MsgCommand.CMPP_SUBMIT ://打包Submit
			MsgSubmit ms=(MsgSubmit)msg;
			dous.writeInt(ms.getTotal_Length());
			dous.writeInt(ms.getCommand_Id());
			dous.writeInt(ms.getSequence_Id());
			
			dous.writeLong(ms.getMsg_Id());
			dous.writeByte(ms.getPk_number());
			dous.writeByte(ms.getPk_total());
			dous.writeByte(ms.getRegistered_Delivery());
			dous.writeByte(ms.getMsg_level());
			
			Utils.writeString(dous, ms.getService_Id(),10);
			dous.writeByte(ms.getFee_UserType());
			Utils.writeString(dous, ms.getFee_terminal_Id(),32);
			dous.writeByte(ms.getFee_terminal_type());
			dous.writeByte(ms.getTP_pId());
			dous.writeByte(ms.getTP_udhi());
			dous.writeByte(ms.getMsg_Fmt());
			
			Utils.writeString(dous, ms.getSrc_Id(),6);
			Utils.writeString(dous, ms.getFeeType(),2);
			Utils.writeString(dous, ms.getFeeCode(),6);
			Utils.writeString(dous, ms.getValId_Time(),17);
			Utils.writeString(dous, ms.getAt_Time(),17);
			
			Utils.writeString(dous, ms.getMsg_src(),21);
			dous.writeByte(ms.getDestUsr_tl());
			
			Utils.writeString(dous, ms.getDest_terminal_Id(),32);
			dous.writeByte(ms.getDest_terminal_type());
			
			dous.writeByte(ms.getMsg_Length());
			Utils.writeString(dous, ms.getMsg_Content(),ms.getMsg_Length());
			Utils.writeString(dous, ms.getLinkID(),20);
			break;
		case MsgCommand.CMPP_SUBMIT_RESP ://打包Submit应答
			MsgSubmitResp msr=(MsgSubmitResp)msg;
			dous.writeInt(msr.getTotal_Length());
			dous.writeInt(msr.getCommand_Id());
			dous.writeInt(msr.getSequence_Id());
			dous.writeLong(msr.getMsg_Id());
			dous.writeInt(msr.getResult());
			//1.原来的Submit消息在内存队列中,在内存中更新后,再存库
			//2.原来的Submit消息己存到DB中,到DB中去更新
			break;
		case MsgCommand.CMPP_DELIVER ://打包Deliver消息
			MsgDeliver md=(MsgDeliver)msg;
			dous.writeInt(md.getTotal_Length());
			dous.writeInt(md.getCommand_Id());
			dous.writeInt(md.getSequence_Id());
			
			dous.writeLong(md.getMsg_Id());
			Utils.writeString(dous, md.getDest_Id(),21);//SP的服务代码
			Utils.writeString(dous, md.getService_Id(), 10);//业务代码
	        
			dous.writeByte(md.getTP_pid());
			dous.writeByte(md.getTP_udhi());
			dous.writeByte(md.getMsg_Fmt());//假设,全部都是GBK
	 
		   Utils.writeString(dous,md.getSrc_terminal_Id(), 32);
		   dous.writeByte(md.getSrc_terminal_type());
			
			dous.writeByte(md.getRegistered_Delivery());
			//如果是状态报报告,那就不一样!
			if(md.getRegistered_Delivery()==1){
				dous.writeLong(md.getMsg_Id_report());
				Utils.writeString(dous,md.getStat(),7);
				Utils.writeString(dous, md.getSubmit_time(),10);
				Utils.writeString(dous, md.getDone_time(),10);
				Utils.writeString(dous, md.getDest_terminal_Id(),32);
				dous.writeInt(md.getSMSC_sequence());
			}else{//发送一段的消息
				dous.writeByte(md.getMsg_Length());//消息长度
				Utils.writeString(dous, md.getMsg_Content(), md.getMsg_Length());//消息内容
			}
			Utils.writeString(dous, md.getLinkID(),20);//写入取linkID
			break;
		case MsgCommand.CMPP_DELIVER_RESP ://打包Deliver_Resp消息
			MsgDeliverResp msd=(MsgDeliverResp)msg;
			dous.writeInt(msd.getTotal_Length());
			dous.writeInt(msd.getCommand_Id());
			dous.writeInt(msd.getSequence_Id());
			dous.writeLong(msd.getMsg_Id());
			dous.writeInt(msd.getResult());
			break;
	      default:
	    	  SysteLog.ERROR("错误消息打包命令", command);
	         }
            dous.flush();
	   return bous.toByteArray();
		}catch(Exception ef){
			SysteLog.ERROR("打包消息出错", ef);
		}
		return null;
	}
	 
	/**
	 * 解包原始数据为具体的消息对象:传入的字节不含消息总长度4个字节
	 * 这个方法肯定是多线程调用的:同步?静态?
	 * @param data:去掉一个消息头长度的消息的原始字节
	 * @return :将原始数据解包成的消息对象
	 */
	public  static MsgHead parseMsg(byte[] data){
		try{
			//先构造一段内存流
		java.io.ByteArrayInputStream bins=new java.io.ByteArrayInputStream(data);
		java.io.DataInputStream dins=new java.io.DataInputStream(bins);
		int command=dins.readInt();//读到类型
		//根据具体的类型来解包
		switch(command){
			case MsgCommand.CMPP_CONNECT ://要解包登陆消息
				MsgLogin ml=new MsgLogin();
				ml.setTotal_Length(data.length+4);
				ml.setCommand_Id(command);
				ml.setSequence_Id(dins.readInt());
				ml.setSource_Addr(Utils.readString(dins, 6));
				byte[] ad=new byte[16];
				dins.read(ad);
				ml.setAuthenticatorSource(ad);
				ml.setVersion(dins.readByte());
				ml.setTimestamp(dins.readInt());
				return ml;
			case MsgCommand.CMPP_CONNECT_RESP ://要解包登陆应答消息	
				MsgLoginResp mlr=new MsgLoginResp();
				mlr.setTotal_Length(data.length+4);
				mlr.setCommand_Id(command);
				mlr.setSequence_Id(dins.readInt());
				mlr.setStatus(dins.readInt());//读取状态
				byte[] rad=new byte[16];
				dins.read(rad); //读取认证串
				
				mlr.setAuthenticatorISMG(rad);
				mlr.setVersion(dins.readByte());
				return mlr;
			case MsgCommand.CMPP_SUBMIT ://要解包Submit消息
				MsgSubmit ms=new MsgSubmit();
				ms.setTotal_Length(data.length+4);
				ms.setCommand_Id(command);
				ms.setSequence_Id(dins.readInt());
				
				ms.setMsg_Id(dins.readLong());
				ms.setPk_number(dins.readByte());
				ms.setPk_number(dins.readByte());
				ms.setRegistered_Delivery(dins.readByte());
				ms.setMsg_level(dins.readByte());
				
				ms.setService_Id(Utils.readString(dins, 10));
				ms.setFee_UserType(dins.readByte());
				ms.setFee_terminal_Id(Utils.readString(dins, 32));
				ms.setFee_terminal_type(dins.readByte());
				ms.setTP_udhi(dins.readByte());
				ms.setTP_pId(dins.readByte());
				ms.setMsg_Fmt(dins.readByte());//消息内容编码格式
				
				ms.setMsg_src(Utils.readString(dins,6));//spId
				ms.setFeeType(Utils.readString(dins,2));
				ms.setFeeCode(Utils.readString(dins,6));
				
				ms.setValId_Time(Utils.readString(dins,17));
				ms.setAt_Time(Utils.readString(dins,17));
				ms.setSrc_Id(Utils.readString(dins,21));
				ms.setDestUsr_tl(dins.readByte());
				ms.setDest_terminal_Id(Utils.readString(dins,32));
				ms.setDest_terminal_type(dins.readByte());
				ms.setMsg_Length(dins.readByte());
				
				ms.setMsg_Content(Utils.readString(dins,ms.getMsg_Length()));
				ms.setLinkID(Utils.readString(dins,20));
				return ms;
			case MsgCommand.CMPP_SUBMIT_RESP ://要解包Submit应答消息
				MsgSubmitResp msr=new MsgSubmitResp();
				msr.setTotal_Length(data.length+4);
				msr.setCommand_Id(command);
				msr.setSequence_Id(dins.readInt());
				
				msr.setMsg_Id(dins.readLong());
				msr.setResult(dins.readInt());
				return msr;
			case MsgCommand.CMPP_DELIVER://如果是deliver消息
				MsgDeliver msd=new MsgDeliver();
				msd.setTotal_Length(data.length+4);//总长
				msd.setCommand_Id(command);
				msd.setSequence_Id(dins.readInt());
				
				msd.setMsg_Id(dins.readLong());//8个字节长的id
			msd.setDest_Id(Utils.readString(dins, 21));//SP的服务代码
			msd.setService_Id(Utils.readString(dins, 10));	
				msd.setTP_pid(dins.readByte());
				msd.setTP_udhi(dins.readByte());
				msd.setMsg_Fmt(dins.readByte());  //假设,全部都是否GBK
				
				msd.setSrc_terminal_Id(Utils.readString(dins, 32));
				msd.setSrc_terminal_type(dins.readByte());
				
				msd.setRegistered_Delivery(dins.readByte());
				//如果是状态报报告,那就不一样!
				if(msd.getRegistered_Delivery()==1){
					msd.setMsg_Id_report(dins.readLong());
					msd.setStat(Utils.readString(dins, 7));
					msd.setSubmit_time(Utils.readString(dins, 10));
					msd.setDone_time(Utils.readString(dins, 10));
					msd.setDest_terminal_Id(Utils.readString(dins, 32));
					msd.setSMSC_sequence(dins.readInt());
				}else{//才是一般消息,即手机发送上来的内容
				msd.setMsg_Length(dins.readByte());//消息长度
				msd.setMsg_Content(Utils.readString(dins, msd.getMsg_Length()));//消息内容
				}
				msd.setLinkID(Utils.readString(dins, 20));//读取linkID
		         return msd;
			case MsgCommand.CMPP_DELIVER_RESP:  //对deliver应答消息的解包  
		         	MsgDeliverResp mdl=new MsgDeliverResp();
		         	mdl.setTotal_Length(data.length+4);
		         	mdl.setCommand_Id(command);
		         	mdl.setSequence_Id(dins.readInt());
					
		         	mdl.setMsg_Id(dins.readLong());
		         	mdl.setResult(dins.readInt());
					return mdl;
			 default:
		    	  SysteLog.ERROR("错误消息解包命令", command);
		          
		}
	 	
		}catch(Exception ef){
			 SysteLog.ERROR("消息解包出错", ef);
		}
		
		return null;
	}
}
